﻿using System;
using System.IO;
using System.Linq;
using System.Xml.Linq;
using System.Xml.XPath;
using Duellum.Core;
using JpLabs.Geometry;

namespace Duellum.Map
{
	public static class DuelMapDecoder
	{
		//static public XAttribute GetAttribute(XNode node, string xpath)
		//{
		//    //var values = (IEnumerable)xmlConfig.XDoc.XPathEvaluate("/duellum/plugin/@package");			
		//    //var packUriText = values.Cast<XAttribute>().Single().Value;			
		//}
		
		static public PointInt ParsePointInt(string value)
		{
			// take '{' and '}' out
			//value = value.Substring(1, value.Length - 2);
			//var values = value.Split(',').Select(s => int.Parse(s)).ToArray();
			
			return new PointInt(
				true,
				value
				.Substring(1, value.Length - 2)
				.Split(',')
				.Select(s => int.Parse(s))
				.ToArray()
			);
			
			//return default(PointInt);
		}
		
		static public DuelMap LoadMap(DuelDomain domain, StreamReader reader)
		{
			XDocument xdoc = XDocument.Load(reader);

			var map = new DuelMap();
			
			try
			{
				var xMapAttributes = xdoc.XPathSelectElements("/duelmap/attributes/*");
				foreach (var xMapAttribute in xMapAttributes)
				{
					map.Attributes[xMapAttribute.Name] = xMapAttribute.Value;
				}

				var xbox = xdoc.XPathSelectElement("/duelmap/shape/box");
				map.Box = new BoundingBoxInt(
					ParsePointInt(xbox.Attribute("lower").Value),
					ParsePointInt(xbox.Attribute("upper").Value)
				);
				
				var xtable = xdoc.XPathSelectElement("/duelmap/table");
				var dict
					= xtable
					.Elements("type")
					.ToDictionary(
						e => int.Parse(e.Attribute("ix").Value),
						e => domain.GetType((DuelTypeId)e.Attribute("id").Value)
					);
				
				var xcontent = xdoc.XPathSelectElement("/duelmap/content");
				var content = Convert.FromBase64String(xcontent.Value);

				#if (DEBUG)
					var watch = System.Diagnostics.Stopwatch.StartNew();
				#endif
				
				for (int i = 0; i<content.Length; i+=4)
				{
					map.AddEntry(
						dict[content[i+3]],
						content[i], content[i+1], content[i+2]
					);
				}

				#if (DEBUG)
					watch.Stop();
					System.Diagnostics.Debug.WriteLine(string.Format("Map R-Tree loaded in {0}ms", watch.ElapsedMilliseconds), "Duellum");
				#endif
				
				//{
				//	var q = map.QueryAll().Where(e => e.Object.Id == (DuelTypeId)"Wall.Wooden").ToArray();
				//}				
			}
			catch (Exception ex) //TODO: catch all exception types is a strong code well
			{
				throw new ArgumentException("Failed to load duel map", ex);
			}
			
			return map;
		}
	}
}
